package com.dd.socket;

import java.util.List;

import org.apache.shiro.session.Session;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mapl.Mapl;
import org.nutz.mvc.Mvcs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.ChannelContext;
import org.tio.core.ChannelContextFilter;
import org.tio.core.Tio;
import org.tio.http.common.HttpRequest;
import org.tio.http.common.HttpResponse;
import org.tio.utils.lock.SetWithLock;
import org.tio.websocket.common.WsRequest;
import org.tio.websocket.server.handler.IWsMsgHandler;

import com.dd.dao.UserDao;
import com.dd.entity.Flock;
import com.dd.entity.SocketMsg;
import com.dd.entity.User;
import com.dd.listener.ShiroSessionListener;
import com.dd.socket.handler.DelFriendMessageHandler;
import com.dd.socket.handler.GroupMessageHandler;
import com.dd.socket.handler.HeartPingMessageHandler;
import com.dd.socket.handler.JoinGroupMessageHandler;
import com.dd.socket.handler.LoginMessageHandler;
import com.dd.socket.handler.OldMessageHandler;
import com.dd.socket.handler.OutGroupMessageHandler;
import com.dd.socket.handler.P2PMessageHandler;
import com.dd.socket.handler.ReqMessageHandler;
import com.dd.utils.SocketMsgUtils;

/**
 * 处理socket请求
 * 
 * @Author: 蛋蛋 [TopCoderMyDream@gmail.com,https://github.com/TopCoderMyDream]
 * @Time:2017/12/12 13:57
 */
@IocBean(name = "accepter")
public class Accepter implements IWsMsgHandler {
	private static Logger log = LoggerFactory.getLogger(Accepter.class);

	@Inject(value = "userDao")
	private UserDao userDao;

	private NutMap handlers = new NutMap();

	/**
	 * @param args
	 * @author tanyaowu
	 */
	public static void main(String[] args) {

	}

	/**
	 *
	 * @author tanyaowu
	 */
	public Accepter() {
		handlers.addv(String.valueOf(Type.REQFRIEND), Mvcs.getIoc().get(ReqMessageHandler.class, "reqMessageHandler"));
		handlers.addv(String.valueOf(Type.DELFRIEND),
				Mvcs.getIoc().get(DelFriendMessageHandler.class, "delFriendMessageHandler"));
		handlers.addv(String.valueOf(Type.JOIN_GROUP_REQ),
				Mvcs.getIoc().get(JoinGroupMessageHandler.class, "joinGroupMessageHandler"));
		handlers.addv(String.valueOf(Type.OUT_GROUP_REQ),
				Mvcs.getIoc().get(OutGroupMessageHandler.class, "outGroupMessageHandler"));
		handlers.addv(String.valueOf(Type.P2P_REQ), Mvcs.getIoc().get(P2PMessageHandler.class, "p2PMessageHandler"));
		handlers.addv(String.valueOf(Type.GROUP_MSG_REQ),
				Mvcs.getIoc().get(GroupMessageHandler.class, "groupMessageHandler"));
		handlers.addv(String.valueOf(Type.LOGIN_REQ_MSG),
				Mvcs.getIoc().get(LoginMessageHandler.class, "loginMessageHandler"));
		handlers.addv(String.valueOf(Type.OLD_MESSAGE_REQ_MSG),
				Mvcs.getIoc().get(OldMessageHandler.class, "oldMessageHandler"));
		handlers.addv(String.valueOf(Type.HEARTPING),
				Mvcs.getIoc().get(HeartPingMessageHandler.class, "heartPingMessageHandler"));
	}

	/**
	 * 握手
	 * 
	 * @param request
	 * @param httpResponse
	 * @param channelContext
	 * @return
	 * @throws Exception
	 */
	@Override
	public HttpResponse handshake(HttpRequest request, HttpResponse httpResponse, ChannelContext channelContext)
			throws Exception {
		log.debug("握手信息");
		// 验证合法性
		String sessionId = request.getParam("sessionId");
		String id = request.getParam("id");
		if (Strings.isBlank(sessionId) || Strings.isBlank(id)) {
			log.debug("用户未登录!");
			return null;
		}
		if (Tio.getChannelContextByBsId(SocketServer.groupContext, sessionId) == null) {
			Tio.bindBsId(channelContext, sessionId);
		} else {
			return null;
		}
		User user = userDao.findbyid(Integer.valueOf(id));
		if (user == null) {
			log.debug("用户不存在!");
			return null;
		}

		Session session = ShiroSessionListener.get(sessionId);
		if (session == null) {
			log.debug("用户未登录!");
			return null;
		}
		channelContext.setAttribute("userName", user.getUsername());
		// 上线
		userDao.online(Integer.valueOf(id));
		// 上线通知
		onLineMsg(user.getUsername(), channelContext);
		return httpResponse;
	}

	/**
	 * 绑定群组
	 * 
	 * @param id
	 * @param context
	 */
	public void bindGroup(int id, ChannelContext context) {
		List<Flock> list = userDao.getFlocks(id);
		if (list != null && list.size() > 0) {
			for (Flock f : list) {
				Tio.bindGroup(context, f.getId().toString());
			}
		}
	}

	/**
	 * 上线通知
	 */
	public void onLineMsg(String name, ChannelContext context) {
		// 直接调用 sendToAll方法会导致错误,不知何种原因
		// Tio.sendToAll(context.getGroupContext(),
		// SocketMsgUtils.madeWsResponse(Type.SUCCESS_MESSAGE_RESP,Json.toJson(NutMap.NEW().setv("msg",name+"上线了!"))));
		SetWithLock<ChannelContext> allConnectedsChannelContexts = Tio.getAllChannelContexts(context.getGroupContext());
		Tio.sendToSet(context.getGroupContext(), allConnectedsChannelContexts,
				SocketMsgUtils.madeWsResponse(Type.SUCCESS_MESSAGE_RESP, Json.toJson(NutMap.NEW()
						.setv("msg", name + "上线了!").setv("count", allConnectedsChannelContexts.getObj().size()))),
				new ChannelContextFilter() {
					@Override
					public boolean filter(ChannelContext channelContext) {
						if (context == channelContext) {
							return false;
						} else {
							return true;
						}
					}
				});

		// for (ChannelContext con : allConnectedsChannelContexts.getObj()){
		// Tio.sendToSet(context.getGroupContext(),
		// SocketMsgUtils.madeWsResponse(Type.SUCCESS_MESSAGE_RESP,Json.toJson(NutMap.NEW().setv("msg",name+"上线了!"))));
		// }
	}

	public void offLineMsg(String name, ChannelContext context) {
		SetWithLock<ChannelContext> allConnectedsChannelContexts = Tio.getAllChannelContexts(context.getGroupContext());
		Tio.sendToSet(context.getGroupContext(), allConnectedsChannelContexts,
				SocketMsgUtils.madeWsResponse(Type.FAIL_MESSAGE_RESP, Json.toJson(NutMap.NEW()
						.setv("msg", name + "下线了!").setv("count", allConnectedsChannelContexts.getObj().size()))),
				new ChannelContextFilter() {
					@Override
					public boolean filter(ChannelContext channelContext) {
						if (context == channelContext) {
							return false;
						} else {
							return true;
						}
					}
				});
	}

	@Override
	public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
		String ss = new String(bytes, "utf-8");
		log.info("收到byte消息:{},{}", bytes, ss);
		SocketMsg socketMsg = Json.fromJson(SocketMsg.class, ss);
		MsgHandlerInterface msgHandler = (MsgHandlerInterface) handlers.get(socketMsg.getAction());
		if (msgHandler != null) {
			msgHandler.handler(socketMsg.getBody().toString(), channelContext);
		} else {
			return null;
		}

		// byte[] bs1 = "收到byte消息".getBytes("utf-8");
		// ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
		// buffer.put(bytes);

		return null;
	}

	@Override
	public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
		Tio.remove(channelContext, "remove");
		Tio.unbindGroup(channelContext);
		Tio.unbindUser(channelContext);

		// 下线
		String userid = channelContext.userid;

		String bsId = channelContext.getBsId();
		if (bsId == null) {
			return null;
		}
		Tio.unbindBsId(channelContext);
		Thread.sleep(2000);
		if (Tio.getChannelContextByBsId(SocketServer.groupContext, bsId) != null) {
			return null;
		}

		if (!Strings.isBlank(userid)) {
			userDao.hide(Integer.valueOf(userid));
		}
		// 下线通知
		offLineMsg(String.valueOf(channelContext.getAttribute("userName")), channelContext);
		return null;
	}

	@Override
	public Object onText(WsRequest wsRequest, String text, ChannelContext channelContext) throws Exception {
		String action = "" + Mapl.cell(Json.fromJson(text), "action");
		if (!Strings.isBlank(action) && !"".equalsIgnoreCase(action)) {
			MsgHandlerInterface msgHandler = (MsgHandlerInterface) handlers.get(action);
			if (msgHandler != null) {
				msgHandler.handler(text, channelContext);
			} else {
				log.debug("非法请求...");
			}
		} else {
			log.debug("非法请求...");
		}
		return null;
	}

	@Override
	public void onAfterHandshaked(HttpRequest request, HttpResponse response, ChannelContext channelContext)
			throws Exception {
		String id = request.getParam("id");
		if (Tio.getChannelContextsByUserid(SocketServer.groupContext, id) != null) {
			Tio.bindUser(channelContext, id);
			// 绑定群组
			bindGroup(Integer.valueOf(id), channelContext);
			return;
		}
		Tio.bindUser(channelContext, id);
		// 绑定用户
		String username = channelContext.getAttribute("userName").toString();
		// 绑定群组
		bindGroup(Integer.valueOf(id), channelContext);

		// 在线人数
		/* sendOnlineCount(channelContext); */

	}

}
